#pragma once
#include <cmath>
#include "gtest/gtest.h"
#include "DataStructure/Common/Constant.h"
#include "../Gauss2DTria6P.h"

using SG::DataStructure::Common::TOLERANCE;
using SG::FEMSolver::Element::Gauss2DTria6P;
using SG::DataStructure::FEM::IntegPoint;

class Gauss2DTria6PTest : public ::testing::Test
{
    public:
    void SetUp () override
    {
        m_integForm = Gauss2DTria6P ();
    }
    protected:
        Gauss2DTria6P m_integForm;
    // 预计算预期的权重值（与源码中 w1、w2 保持一致，避免硬编码重复）
    const double EXPECTED_W1 = 0.109951743655322 / 2.0; 
    const double EXPECTED_W2 = 0.223381589678011 / 2.0;
    // 参考单元（标准三角形）的预期权重总和（源码注释明确 “权重和为 1/2”）
    const double EXPECTED_WEIGHT_SUM = 0.5;
};

// 测试积分点数量是否正确（六点）
TEST_F (Gauss2DTria6PTest, GetPointSize_ShouldReturn6)
{
    ASSERT_EQ (m_integForm.GetPointSize (), 6U); // 使用 unsigned 比较，与 std::size_t 类型匹配
}

// 测试逐个验证 6 个积分点的坐标（x/y/z）和权重是否符合预期
TEST_F (Gauss2DTria6PTest, GetPoint_ShouldMatchExpectedValues)
{
    IntegPoint point;
    // 第 1 个积分点：(0.816847572980459, 0.091576213509771, 0.0)，权重 w1
    point = m_integForm.GetPoint (0);
    ASSERT_NEAR (point.m_x, 0.816847572980459, TOLERANCE);
    ASSERT_NEAR (point.m_y, 0.091576213509771, TOLERANCE);
    ASSERT_NEAR (point.m_z, 0.0, TOLERANCE);
    ASSERT_NEAR (point.m_weight, EXPECTED_W1, TOLERANCE);
    // 第 2 个积分点：(0.091576213509771, 0.816847572980459, 0.0)，权重 w1
    point = m_integForm.GetPoint (1);
    ASSERT_NEAR (point.m_x, 0.091576213509771, TOLERANCE);
    ASSERT_NEAR (point.m_y, 0.816847572980459, TOLERANCE);
    ASSERT_NEAR (point.m_z, 0.0, TOLERANCE);
    ASSERT_NEAR (point.m_weight, EXPECTED_W1, TOLERANCE);
    // 第 3 个积分点：(0.091576213509771, 0.091576213509771, 0.0)，权重 w1
    point = m_integForm.GetPoint (2);
    ASSERT_NEAR (point.m_x, 0.091576213509771, TOLERANCE);
    ASSERT_NEAR (point.m_y, 0.091576213509771, TOLERANCE);
    ASSERT_NEAR (point.m_z, 0.0, TOLERANCE);
    ASSERT_NEAR (point.m_weight, EXPECTED_W1, TOLERANCE);
    // 第 4 个积分点：(0.108103018168070, 0.445948490915965, 0.0)，权重 w2
    point = m_integForm.GetPoint (3);
    ASSERT_NEAR (point.m_x, 0.108103018168070, TOLERANCE);
    ASSERT_NEAR (point.m_y, 0.445948490915965, TOLERANCE);
    ASSERT_NEAR (point.m_z, 0.0, TOLERANCE);
    ASSERT_NEAR (point.m_weight, EXPECTED_W2, TOLERANCE);
    // 第 5 个积分点：(0.445948490915965, 0.108103018168070, 0.0)，权重 w2
    point = m_integForm.GetPoint (4);
    ASSERT_NEAR (point.m_x, 0.445948490915965, TOLERANCE);
    ASSERT_NEAR (point.m_y, 0.108103018168070, TOLERANCE);
    ASSERT_NEAR (point.m_z, 0.0, TOLERANCE);
    ASSERT_NEAR (point.m_weight, EXPECTED_W2, TOLERANCE);
    // 第 6 个积分点：(0.445948490915965, 0.445948490915965, 0.0)，权重 w2
    point = m_integForm.GetPoint (5);
    ASSERT_NEAR (point.m_x, 0.445948490915965, TOLERANCE);
    ASSERT_NEAR (point.m_y, 0.445948490915965, TOLERANCE);
    ASSERT_NEAR (point.m_z, 0.0, TOLERANCE);
    ASSERT_NEAR (point.m_weight, EXPECTED_W2, TOLERANCE);
}

// 测试所有积分点的权重总和是否符合参考单元面积（1/2）
TEST_F (Gauss2DTria6PTest, WeightSum_ShouldBeEqualToReferenceTriangleArea)
{
    double weightSum = 0.0;
    const std::size_t pointCount = m_integForm.GetPointSize ();
    // 累加所有积分点的权重
    for (std::size_t i = 0; i < pointCount; ++i)
    {
        weightSum += m_integForm.GetPoint (i).m_weight;
    }
    // 验证权重和是否接近 1/2（允许浮点误差）
    ASSERT_NEAR (weightSum, EXPECTED_WEIGHT_SUM, TOLERANCE);
}

// 测试GetPoints () 接口返回的积分点数组是否正确（与 GetPoint () 一致性校验）
TEST_F (Gauss2DTria6PTest, GetPoints_ShouldMatchGetPointResults)
{
    auto& pointArray = m_integForm.GetPoints ();
    const std::size_t pointCount = m_integForm.GetPointSize ();
    
    // 验证数组大小与积分点数量一致
    ASSERT_EQ (pointArray.size (), pointCount);
    
    // 逐个验证数组中的点与 GetPoint () 返回的点一致
    for (std::size_t i = 0; i < pointCount; ++i)
    {
        const auto& arrayPoint = pointArray [i];
        const auto& getPoint = m_integForm.GetPoint (i);
        ASSERT_NEAR(arrayPoint.m_x, getPoint.m_x, TOLERANCE);
        ASSERT_NEAR(arrayPoint.m_y, getPoint.m_y, TOLERANCE);
        ASSERT_NEAR(arrayPoint.m_z, getPoint.m_z, TOLERANCE);
        ASSERT_NEAR(arrayPoint.m_weight, getPoint.m_weight, TOLERANCE);
    }
}